/*
 ************************************************************************************************
 *                                                                                              *
 *  OSA cooperative RTOS for Microchip PIC-controllers: PIC10/12/16/18/24/dsPIC                 *
 *                                                                                              *
 *  URL:        http://wiki.pic24.ru/doku.php/en/osa/ref/intro                                  *
 *              http://picosa.narod.ru                                                          *
 *                                                                                              *
 *----------------------------------------------------------------------------------------------*
 *                                                                                              *
 *  File:       osa.c                                                                           *
 *                                                                                              *
 *  Compilers:  HT-PICC STD                                                                     *
 *              HT-PICC18 STD                                                                   *
 *              Microchip C18                                                                   *
 *              Microchip C30                                                                   *
 *                                                                                              *
 *  Programmer: Timofeev Victor                                                                 *
 *              osa@pic24.ru, testerplus@mail.ru                                                *
 *                                                                                              *
 *  Definition: This file contains all system variables and functions definitions.              *
 *                                                                                              *
 *                                                                                              *
 ************************************************************************************************
 */




#include <OSA.h>





/*
 ************************************************************************************************
 *                                                                                              *
 *  V A R I A B L E S   D E F I N I T I O N                                                     *
 *                                                                                              *
 ************************************************************************************************
 */

//------------------------------------------------------------------------------
#ifdef __OSAMCC18__
#pragma udata access ACCESS
#endif
//------------------------------------------------------------------------------



NEAR    OST_SYSTEM_FLAGS             OS_Flags           __osa30_near;   // System state flags
NEAR   _OST_INT_TYPE                _OS_temp            __osa30_near;   // For internal purpose

#ifndef __OSAPICC12__
NEAR   _OST_INT_TYPE                _OS_tempH           __osa30_near;   // For internal purpose
#endif


#if defined(_OS_CUR_FLAGS_IN_OS_state)
NEAR    OST_TASK_STATE               OS_state           __osa30_near;
#endif

        OST_TASK_POINTER    NEAR    _OS_CurTask         __osa30_near;   // Pointer to current task
                                                                        // descriptor.

//------------------------------------------------------------------------------
#if OS_TIMERS24 > 0
OS_BANK _OST_INT_TYPE                OS_Ticks           __osa30_near;
#endif
//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
#ifdef __OSAMCC18__
#pragma udata
#endif
//------------------------------------------------------------------------------


// dynamic timers

//------------------------------------------------------------------------------
#ifdef OS_ENABLE_DTIMERS
//------------------------------------------------------------------------------

    #if OS_BANK_OS == 0
        #ifdef __OSAMCC18__
        #pragma udata access os_bsems
        #endif
    #endif

    OS_BANK OST_DTIMER_CB               _OS_DTimers         __osa30_near;   // Pointer to list of

    #if OS_BANK_OS == 0
        #ifdef __OSAMCC18__
        #pragma udata
        #endif
    #endif


    #if defined(__OSAMCC30__)

    OS_BANK OST_DTIMER                * _OS_DTimerWork      __osa30_near;
                                                                        // Temp var for work with
                                                                        // list of dynamic
                                                                        // timers in ISR
    #endif
//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
#if !defined(OS_DISABLE_PRIORITY)
//------------------------------------------------------------------------------
        #if OS_BANK_OS == 0
            #ifdef __OSAMCC18__
            #pragma udata access os_bsems
            #endif
        #endif

        OST_TASK_POINTER    OS_BANK _OS_BestTask        __osa30_near;   // Pointer to ready task
                                                                        // with highest priority
                                                                        // (used in OS_Sched)
        OST_TASK_POINTER    OS_BANK _OS_LastTask        __osa30_near;   // Pointer to last
                                                                        // executed task
OS_BANK _OST_INT_TYPE               _OS_best_priority   __osa30_near;

        #if OS_BANK_OS == 0
            #ifdef __OSAMCC18__
            #pragma udata
            #endif
        #endif

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------







/*
 *------------------------------------------*
 * Binary semaphores                        *
 *------------------------------------------*
 */
#if OS_BSEMS > 0
            #if OS_BANK_BSEM == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_bsems
                #endif
            #endif

OS_BSEM_BANK    _OST_INT_TYPE   OS_BSems[(OS_BSEMS + _OST_INT_SIZE-1) / _OST_INT_SIZE] __osa30_near;

            #if OS_BANK_BSEM == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif





/*
 *------------------------------------------*
 * Task descriptors                         *
 *------------------------------------------*
 */
            #if OS_BANK_TASKS == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_tasks
                #endif
            #endif

OS_TASKS_BANK   OST_TCB             OS_TaskVars[OS_TASKS]   __osa30_near;

            #if OS_BANK_TASKS == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif




/*
 *------------------------------------------*
 * Timeouts for old style static timers     *
 *------------------------------------------*
 */

#if OS_TIMERS > 0

            #if OS_BANK_TIMEOUTS == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_timeout
                #endif
            #endif

OS_TIMEOUTS_BANK _OST_INT_TYPE OS_Timeouts[(OS_TIMERS + _OST_INT_SIZE - 1) / _OST_INT_SIZE] __osa30_near;

            #if OS_BANK_TIMEOUTS == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif




/*
 *------------------------------------------*
 * 32-bit old style static timers           *
 *------------------------------------------*
 */
#if OS_TIMERS32 > 0

            #if OS_BANK_TIMERS32 == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_timers32
                #endif
            #endif

OS_TIMERS32_BANK    __osa_uint32    OS_Timers32[OS_TIMERS32]    __osa30_near;

            #if OS_BANK_TIMERS32 == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif


/*
 *------------------------------------------*
 * 24-bit old style static timers           *
 *------------------------------------------*
 */
#if OS_TIMERS24 > 0

            #if OS_BANK_TIMERS24 == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_timers24
                #endif
            #endif

OS_TIMERS24_BANK    __osa_uint16    OS_Timers24[OS_TIMERS24]    __osa30_near;

            #if OS_BANK_TIMERS24 == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif


/*
 *------------------------------------------*
 * 16-bit old style static timers           *
 *------------------------------------------*
 */
#if OS_TIMERS16 > 0

            #if OS_BANK_TIMERS16 == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_timers16
                #endif
            #endif

OS_TIMERS16_BANK    __osa_uint16    OS_Timers16[OS_TIMERS16]    __osa30_near;

            #if OS_BANK_TIMERS16 == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif


/*
 *------------------------------------------*
 *  8-bit old style static timers           *
 *------------------------------------------*
 */
#if OS_TIMERS8 > 0

            #if OS_BANK_TIMERS8 == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_timers8
                #endif
            #endif

OS_TIMERS8_BANK     __osa_uint8     OS_Timers8[OS_TIMERS8]      __osa30_near;

            #if OS_BANK_TIMERS8 == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif
//------------------------------------------------------------------------------



/*
 *------------------------------------------*
 * Static timers                            *
 *------------------------------------------*
 */
#if OS_STIMERS > 0

            #if OS_BANK_STIMERS == 0
                #ifdef __OSAMCC18__
                #pragma udata access os_stimers
                #endif
            #endif

OS_STIMERS_BANK     _OST_STIMER     OS_STimers[OS_STIMERS]      __osa30_near;

            #if OS_BANK_STIMERS == 0
                #ifdef __OSAMCC18__
                #pragma udata
                #endif
            #endif
#endif










/*
 ************************************************************************************************
 *                                                                                              *
 *  I N C L U D E   C O M P I L E R   S P E C I F I E D   D E F I N I T I O N S                 *
 *                                                                                              *
 ************************************************************************************************
 */

#if defined(__OSAPICC18__)
    #include <port\osa_picc18.c>         // HT-PICC18
#elif defined(__OSAMCC18__)
    #include <port\osa_mcc18.c>          // MPLAB C18
#elif defined(__OSAMCC30__)
    #include <port\osa_mcc30.c>          // MPLAB C30
#elif defined(__OSAPICC12__)
    #include <port\osa_picc12.c>         // HT_PICC for 12-bit PICs
#elif defined(__OSAPICC__)
    #include <port\osa_picc16.c>         // HT_PICC
#else
    #error "Unknown compiler!"
#endif







/************************************************************************************************
 *                                                                                              *
 *                                                                                              *
 *                         F U N C T I O N   D E F I N I T I O N S                              *
 *                                                                                              *
 *                                                                                              *
 ************************************************************************************************/








/*
 ************************************************************************************************
 *                                                                                              *
 *                            C O U N T I N G    S E M A P H O R E S                            *
 *                                                                                              *
 ************************************************************************************************
 */
//------------------------------------------------------------------------------
#ifdef OS_ENABLE_CSEM
//------------------------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  bit _OS_Csem_Check(OST_CSEM *pCSem)                                         *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Check counting semaphore for non-zero value. This function  *
 *                  applied to 2- or 4-bytes semaphores. Single byte semaphore  *
 *                  checking described in "service\osa_scem.h"                  *
 *                                                                              *
 *                                                                              *
 *  parameters:     pCSem - pointer to counting semaphore                       *
 *                                                                              *
 *  on return:      1 - semaphore not eq to zero                                *
 *                  0 - semaphore is zero                                       *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if OS_CSEM_SIZE > 1
//------------------------------------------------------------------------------

    bit _OS_Csem_Check(OST_CSEM *pCSem)
    {
        _OS_temp = OS_DI();
        if (*pCSem) _OS_temp |= 1;
        OS_RI(_OS_temp);
        if (_OS_temp & 1) return 1;
        return 0;
    }

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Csem_Signal (OST_CSEM *pCSem)                                      *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  Increase counting semaphore. Set EventError if csem is FF...                *
 *                                                                              *
 *                                                                              *
 *  parameters:     pCSem - pointer to counting semaphore                       *
 *                                                                              *
 *  on return:      OS_IsEventError()                                           *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if !defined(_OS_Csem_Signal_DEFINED)
//------------------------------------------------------------------------------

    void _OS_Csem_Signal (OST_CSEM *pCSem)
    {
        __OS_CSEM_DI();
        OS_Flags.bEventError = 0;

        (*pCSem)++;
        if (!*pCSem) {
            (*pCSem) = -1;
            OS_Flags.bEventError = 1;
        }
        __OS_CSEM_RI();
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_Csem_Signal)
//------------------------------------------------------------------------------




/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_Csem_Signal_I (OST_CSEM *pCSem)                                   *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Copy of _OS_Csem_Signal function for calling from interrupt *
 *                                                                              *
 *  parameters:     pCSem - pointer to counting semaphore                       *
 *                                                                              *
 *  on return:      OS_IsEventError()                                           *
 *                                                                              *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if defined(OS_ENABLE_INT_CSEM) && !defined(_OS_Csem_Signal_I_DEFINED)
//------------------------------------------------------------------------------
    void _OS_Csem_Signal_I (OST_CSEM *pCSem)
    {
        OS_Flags.bEventError = 0;

        (*pCSem)++;
        if (!*pCSem) {
            (*pCSem) = -1;
            OS_Flags.bEventError = 1;
        }
    }
//------------------------------------------------------------------------------
#endif  // OS_ENABLE_INT_CSEM
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
#endif  // OS_CSEM_ENABLE
//------------------------------------------------------------------------------
















/*
 ************************************************************************************************
 *                                                                                              *
 *                         C R I T I C A L   S E C T I O N S                                    *
 *                                                                                              *
 ************************************************************************************************
 */

//------------------------------------------------------------------------------
#ifdef OS_ENABLE_CRITICAL_SECTION
//------------------------------------------------------------------------------

/*
 ********************************************************************************
 *                                                                              *
 *   void OS_EnterCriticalSection (void)                                        *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *   description:   Enter critical section.                                     *
 *                  This function disables interrupts (with saving current      *
 *                  state) and sets system flag bInCriticalSection              *
 *                                                                              *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if !defined(OS_EnterCriticalSection_DEFINED)
//------------------------------------------------------------------------------

    void OS_EnterCriticalSection (void)
    {
        _OST_INT_TYPE temp;

        temp = OS_DI();
        OS_Flags.bInCriticalSection = 1;

    }

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------




/*
 ********************************************************************************
 *                                                                              *
 *   void OS_LeaveCriticalSection (void)                                        *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Leave critical section.                                     *
 *                  This function restore interrupt state from OS_Flag temp bits*
 *                  and clears system flag bInCriticalSection                   *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if !defined(OS_LeaveCriticalSection_DEFINED)
//------------------------------------------------------------------------------

    void OS_LeaveCriticalSection (void)
    {
        char temp;

        OS_Flags.bInCriticalSection = 0;

        OS_RI(temp);
    }

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
#endif  //  OS_ENABLE_CRITICAL_SECTION
//------------------------------------------------------------------------------
















/*
 ************************************************************************************************
 *                                                                                              *
 *                                   D E L A Y S   I N   T A S K                                *
 *                                                                                              *
 ************************************************************************************************
 */

//------------------------------------------------------------------------------
#ifdef OS_ENABLE_TTIMERS
//------------------------------------------------------------------------------

/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_InitDelay (_OST_TTIMER Delay)                                     *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel)                 *
 *                                                                              *
 *                  Init task timer delay.Set timer variable in task descriptor,*
 *                  sets bit bDelay and clears bit bCanContinue.                *
 *                                                                              *
 *                  _OS_CurTask must point to descriptor.                       *
 *                                                                              *
 *                                                                              *
 *  parameters:     Delay   - time of delay in system ticks                     *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */




//------------------------------------------------------------------------------
#if !defined(_OS_InitDelay_DEFINED)
//------------------------------------------------------------------------------

    void _OS_InitDelay (_OST_TTIMER Delay)
    {

        _OS_CurTask->State.bCanContinue = 0;
        _OS_CurTask->State.bDelay = 0;

        if (Delay)
        {
            Delay ^= -1;
            Delay ++;
            _OS_CurTask->Timer = Delay;
            _OS_CurTask->State.bReady = 1;
            _OS_CurTask->State.bDelay = 1;
        }
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_InitDelay_DEFINED)
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
#endif  // #ifdef OS_TIMER
//------------------------------------------------------------------------------

















/************************************************************************************************
 *                                                                                              *
 *                            S Y S T E M   F U N C T I O N S                                   *
 *                                                                                              *
 ************************************************************************************************/



/*
 ********************************************************************************
 *                                                                              *
 *   void OS_Init (void)                                                        *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel)                 *
 *                                                                              *
 *                  Initialize all system variables:                            *
 *                  - Clear all binary semaphores                               *
 *                  - Free all task descriptors                                 *
 *                  - Clear all timeouts for old style static timers            *
 *                  - Set _OS_LastTask and _OS_CurTask variables at last task   *
 *                    descriptor                                                *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      _OSCurTask points to last task descriptor.                  *
 *                                                                              *
 *  Overloaded in:  -                                                           *
 *                                                                              *
 ********************************************************************************
 */


void OS_Init (void)
{
    *((NEAR _OST_INT_TYPE*)&OS_Flags) = 0;

    OS_Init_ProcSpec();     /* Specific controller type's init operations   */



    #if !defined(OS_DISABLE_PRIORITY)

        _OS_LastTask = (OS_TASKS_BANK OST_TASK_POINTER) &OS_TaskVars[OS_TASKS - 1];

    #endif



    /*--------------------------------------*
     *                                      *
     *  Zero all old style static timers    *
     *                                      *
     *--------------------------------------*/

    #if OS_TIMERS > 11*8 || ((OS_TIMERS > 0) && defined(__OSAMCC30__))
        _OS_temp = sizeof(OS_Timeouts);
        do {
            OS_Timeouts[_OS_temp-1] = 0;
        } while (--_OS_temp);
    #else
        #if OS_TIMERS > 0
            OS_Timeouts[0] = 0;
        #endif

        #if OS_TIMERS > 1*8
            OS_Timeouts[1] = 0;
        #endif

        #if OS_TIMERS > 2*8
            OS_Timeouts[2] = 0;
        #endif

        #if OS_TIMERS > 3*8
            OS_Timeouts[3] = 0;
        #endif

        #if OS_TIMERS > 4*8
            OS_Timeouts[4] = 0;
        #endif

        #if OS_TIMERS > 5*8
            OS_Timeouts[5] = 0;
        #endif

        #if OS_TIMERS > 6*8
            OS_Timeouts[6] = 0;
        #endif

        #if OS_TIMERS > 7*8
            OS_Timeouts[7] = 0;
        #endif

        #if OS_TIMERS > 8*8
            OS_Timeouts[8] = 0;
        #endif

        #if OS_TIMERS > 9*8
            OS_Timeouts[9] = 0;
        #endif

        #if OS_TIMERS > 10*8
            OS_Timeouts[10] = 0;
        #endif

    #endif


    /*--------------------------------------*
     *                                      *
     *  Clear list of dynamic timers        *
     *                                      *
     *--------------------------------------*/

    #if defined(OS_ENABLE_DTIMERS)
        *((OS_BANK _OST_INT_TYPE*)&_OS_DTimers.Flags) = 0;
        _OS_DTimers.Flags.bActive = 1;
    #endif



    /*--------------------------------------*
     *                                      *
     *  Zero all binary semaphores          *
     *                                      *
     *--------------------------------------*/

    #if OS_BSEMS > 11*8 || ((OS_BSEMS > 0) && defined(__OSAMCC30__))
        _OS_temp = sizeof(OS_BSems) / sizeof(_OST_INT_TYPE);
        do {
            OS_BSems[_OS_temp-1] = 0;
        } while (--_OS_temp);
    #else
        #if OS_BSEMS > 0
            OS_BSems[0] = 0;
        #endif

        #if OS_BSEMS > 1*8
            OS_BSems[1] = 0;
        #endif

        #if OS_BSEMS > 2*8
            OS_BSems[2] = 0;
        #endif

        #if OS_BSEMS > 3*8
            OS_BSems[3] = 0;
        #endif

        #if OS_BSEMS > 4*8
            OS_BSems[4] = 0;
        #endif

        #if OS_BSEMS > 5*8
            OS_BSems[5] = 0;
        #endif

        #if OS_BSEMS > 6*8
            OS_BSems[6] = 0;
        #endif

        #if OS_BSEMS > 7*8
            OS_BSems[7] = 0;
        #endif

        #if OS_BSEMS > 8*8
            OS_BSems[8] = 0;
        #endif

        #if OS_BSEMS > 9*8
            OS_BSems[9] = 0;
        #endif

        #if OS_BSEMS > 10*8
            OS_BSems[10] = 0;
        #endif
    #endif


    /*--------------------------------------*
     *                                      *
     *  Zero all task descriptors           *
     *                                      *
     *--------------------------------------*/

    #if OS_TASKS > 10
        _OS_CurTask = (OST_TASK_POINTER) OS_TaskVars;
        _OS_temp = OS_TASKS;
        do {
            _OS_CurTask->State.bEnable = 0;
            _OS_CurTask ++;
        } while (--_OS_temp);
    #else

        #ifdef OS_DISABLE_PRIORITY
            _OS_CurTask = (OST_TASK_POINTER)&OS_TaskVars[OS_TASKS-1];
        #endif

        OS_TaskVars[0].State.bEnable = 0;

        #if OS_TASKS > 1
           OS_TaskVars[1].State.bEnable = 0;
        #endif

        #if OS_TASKS > 2
           OS_TaskVars[2].State.bEnable = 0;
        #endif

        #if OS_TASKS > 3
           OS_TaskVars[3].State.bEnable = 0;
        #endif

        #if OS_TASKS > 4
           OS_TaskVars[4].State.bEnable = 0;
        #endif

        #if OS_TASKS > 5
           OS_TaskVars[5].State.bEnable = 0;
        #endif

        #if OS_TASKS > 6
           OS_TaskVars[6].State.bEnable = 0;
        #endif

        #if OS_TASKS > 7
           OS_TaskVars[7].State.bEnable = 0;
        #endif

        #if OS_TASKS > 8
           OS_TaskVars[8].State.bEnable = 0;
        #endif

        #if OS_TASKS > 9
           OS_TaskVars[9].State.bEnable = 0;
        #endif

    #endif

}
















/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_Task_Create(_OST_INT_TYPE priority, OST_CODE_POINTER TaskAddr)    *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *   description:   (Internal function called by system kernel from service     *
 *                  OS_Task_Create)                                             *
 *                  Create task in free descriptor.                             *
 *                                                                              *
 *  parameters:     priority - value from 0 (highest) to 7 (lowest)             *
 *                  TaskAddr - pointer to C-function that contains task         *
 *                                                                              *
 *  on return:      check OS_IsError                                            *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#if !defined(_OS_Task_Create_DEFINED)
//------------------------------------------------------------------------------

    void _OS_Task_Create(_OST_INT_TYPE priority, OST_CODE_POINTER TaskAddr)
    {
        OST_TASK_POINTER Task;

        OS_Flags.bError = 0;

        #if defined(OS_DISABLE_PRIORITY)
        priority = 0;   // To increase scheduler speed
        #endif



        /*--------------------------------------*
         *                                      *
         *  Start search from first task in     *
         *  OS_TASKS descriptors.               *
         *                                      *
         *--------------------------------------*/
        Task = (OST_TASK_POINTER)OS_TaskVars;
        _OS_temp = OS_TASKS;

        do {

            if (!Task->State.bEnable)               // Is descriptor free?
            {                                       // Yes
                ((OST_TASK_STATE*)&priority)->bEnable = 1;
                ((OST_TASK_STATE*)&priority)->bReady = 1;

                Task->pTaskPointer = TaskAddr;

                #ifdef OS_ENABLE_TTIMERS
                    Task->Timer = 0;
                #endif

                #ifdef __OSA18__
                    Task->cTempFSR1 = 0;
                #endif

                *((OS_TASKS_BANK char*)&Task->State) = priority;

                // Now FSR points to created task descriptor
                // disabled since 90111: _fsr = (_FSR_TYPE)Task;

                OS_Flags.bError = 0;

                return ;

            }

            Task ++;

        } while (_OS_temp--);

        // There is no free descriptor. Task was not created.

        OS_Flags.bError = 1;

        return ;
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_Task_Create_DEFINED)
//------------------------------------------------------------------------------
























/*
 ********************************************************************************
 *                                                                              *
 *   void OS_Timer (void)                                                       *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    System timer. Should be called in periodical place in       *
 *                  program. This function increases all static, dynamic and    *
 *                  task timers.                                                *
 *                                                                              *
 *                  User can define OS_ENABLE_OS_TIMER constant in OSAcfg.h to  *
 *                  make this function in-line. This will increase speed and    *
 *                  reduce used ROM.                                            *
 *                                                                              *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  Overloaded in:  -                                                           *
 *                                                                              *
 ********************************************************************************
 */

//-----------------------------------------------------------------
#ifdef OS_ENABLE_OS_TIMER
#ifndef OS_USE_INLINE_TIMER
//-----------------------------------------------------------------
void OS_Timer (void)
{
    __OS_TimerInline(0);
}
//-----------------------------------------------------------------
#endif  // OS_ENABLE_OS_TIMER
#endif  // OS_USE_INLINE_TIMER
//-----------------------------------------------------------------








/*
 ********************************************************************************
 *                                                                              *
 *  bit _OS_CheckEvent (char bEvent)                                            *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  waiting services)                                           *
 *                                                                              *
 *                  Check condition of bEvent. Accordint to bEvent value and    *
 *                  current state of bReady, bDelay and bCanContinue flags,     *
 *                  task becames ready to execute or still remains in waiting   *
 *                  mode.                                                       *
 *                                                                              *
 *  parameters:     bEvent - zero, or non-zero condition                        *
 *                                                                              *
 *  on return:      1 - when condition is true, or timeout occured              *
 *                  0 - condition is false and no timeout                       *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if !defined(_OS_CheckEvent_DEFINED)
//------------------------------------------------------------------------------

    bit _OS_CheckEvent (char bEvent)
    {
        OS_Flags.bTimeout = 0;

        if (bEvent)
        {

            if (_OS_CurTask->State.bReady)
            {
                #ifdef OS_ENABLE_TTIMERS
                    _OS_CurTask->State.bDelay = 0;
                #endif

                return 1;

            }

            _OS_bTaskReady = 1;

        } else {
            _OS_bTaskReady = 0;
        }

        #ifdef OS_ENABLE_TTIMERS

            if (_OS_CurTask->State.bTimeout && _OS_CurTask->State.bCanContinue)
            {
                OS_Flags.bTimeout = 1;

                return 1;

            }

        #endif

        return 0;

    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_CheckEvent_DEFINED)
//------------------------------------------------------------------------------













/************************************************************************************************
 *                                                                                              *
 *                     W O R K   W I T H   D Y N A M I C   T I M E R S                          *
 *                                                                                              *
 ************************************************************************************************/

//-----------------------------------------------------------------
#ifdef OS_ENABLE_DTIMERS
//-----------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Dtimer_Create (OST_DTIMER *dtimer)                                 *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_Dtimer_Create)                                   *
 *                                                                              *
 *                  Add dynamic timer into list of active dynamic timers. This  *
 *                  timer will be added at first position in list.              *
 *                                                                              *
 *                                                                              *
 *  parameters:     dtimer - pointer to dynamic timer.                          *
 *                  (for PICC16 can be allocated only in bank0 and bank1)       *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */


//-----------------------------------------------------------------
#if !defined(_OS_Dtimer_Create_DEFINED)
//-----------------------------------------------------------------

    void _OS_Dtimer_Create (OST_DTIMER *dtimer)
    {
        _OS_temp = OS_DI();

        dtimer->Next = _OS_DTimers.Next;
        dtimer->Flags = _OS_DTimers.Flags;
        dtimer->Timer = 0;

        _OS_DTimers.Next = (OST_DTIMER*)dtimer;
        _OS_DTimers.Flags.bNextEnable = 1;

        OS_RI(_OS_temp);
    }

//-----------------------------------------------------------------
#endif  // !defined(_OS_Dtimer_Create_DEFINED)
//-----------------------------------------------------------------



/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Dtimer_Delete (OST_DTIMER *dtimer)                                 *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_Dtimer_Delete)                                   *
 *                                                                              *
 *                  Delete dynamic timer from list of active timers. It is      *
 *                  recommended to delete all unused dynamic timers to avoid    *
 *                  speed down.                                                 *
 *                                                                              *
 *  parameters:     dtimer - pointer to deleting dynamic timer                  *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                  "port\osa_picc16.c"                                         *
 *                  "port\osa_picc18.c"                                         *
 *                  "port\osa_mcc18.c"                                          *
 *                  "port\osa_mcc30.c"                                          *
 *                                                                              *
 ********************************************************************************
 */


//-----------------------------------------------------------------
#if !defined(_OS_Dtimer_Delete_DEFINED)
//-----------------------------------------------------------------

    void _OS_Dtimer_Delete (OST_DTIMER *dtimer)
    {

        OST_DTIMER *ptcb;

        // Search current timer in list

        ptcb = (OST_DTIMER*)&_OS_DTimers;

        while (ptcb->Flags.bNextEnable)
        {
            if (ptcb->Next == dtimer)               // Current timer found
            {
                ptcb->Next = dtimer->Next;

                if (!dtimer->Flags.bNextEnable)
                    ptcb->Flags.bNextEnable = 0;

                dtimer->Flags.bActive = 0;

                return;

            }
            ptcb = ptcb->Next;
        }
    }

//-----------------------------------------------------------------
#endif  // !defined(_OS_Dtimer_Delete_DEFINED)
//-----------------------------------------------------------------




//-----------------------------------------------------------------
#endif  //  OS_ENABLE_DTIMERS
//-----------------------------------------------------------------






































/************************************************************************************************
 *                                                                                              *
 *     S I M P L E    M E S S A G E S   C H E C K                                               *
 *                                                                                              *
 ************************************************************************************************/

/*
 ********************************************************************************
 *                                                                              *
 *  bit _OS_SMsg_Check(OST_SMSG* smsg)                                          *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_SMsg_Check)                                      *
 *                                                                              *
 *                  This function enabled when OS_ENABLE_INT_SMSG constant      *
 *                  defined and size of simple message greater than 1. This     *
 *                  function used to prevent smsg changing by interrupt while   *
 *                  checking.                                                   *
 *                                                                              *
 *  parameters:     smsg - pointer to simple message                            *
 *                                                                              *
 *  on return:      1 - simple message present                                  *
 *                  0 - simple message absent                                   *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.h"                                         *
 *                  "port\osa_picc16.h"                                         *
 *                  "port\osa_picc18.h"                                         *
 *                  "port\osa_mcc18.h"                                          *
 *                  "port\osa_mcc30.h"                                          *
 *                                                                              *
 ********************************************************************************
 */


#if defined(OS_ENABLE_INT_SMSG) && (OS_SMSG_SIZE > 1)

    bit _OS_SMsg_Check(OST_SMSG* smsg)
    {
        _OS_temp = OS_DI();
        if (*smsg) _OS_temp |= 1;
        OS_RI(_OS_temp);

        return _OS_temp & 1;
    }

#endif











/************************************************************************************************
 *                                                                                              *
 *     M E S S A G E   Q U E U E S                                                              *
 *                                                                                              *
 ************************************************************************************************/


//------------------------------------------------------------------------------
#if defined(OS_ENABLE_SQUEUE) && !defined(OS_QUEUE_SQUEUE_IDENTICAL)
//------------------------------------------------------------------------------



/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_SQueue_Send (OST_SQUEUE *pSQueue, OST_SMSG SMsg)                   *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service _OS_SendSQueue)                                     *
 *                                                                              *
 *                  Add message into queue of simple messages. Delete first     *
 *                  message if there is no free room to add new message.        *
 *                  Service OS_SQueue_Send before adding new message checks for *
 *                  free room. Thus messages will not deleted accidentally.     *
 *                                                                              *
 *                                                                              *
 *  parameters:     pSQueue      - pointer to queue descriptor                  *
 *                  SMsg        - simple message to be added                    *
 *                                                                              *
 *  on return:      OS_IsEventError() return 1, if first message was pushed out *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#if !defined(_OS_SQueue_Send_DEFINED)
//------------------------------------------------------------------------------

    void _OS_SQueue_Send (OST_SQUEUE *pSQueue, OST_SMSG SMsg)
    {
        OST_QUEUE_CONTROL   q;          // Temp variable to increase speed
        _OST_INT_TYPE temp;

        __OS_QUEUE_DI();

        q = pSQueue->Q;
        OS_Flags.bEventError = 0;                   // First we clear error flag


        //------------------------------------------------------
        // If there is no free room in queue, then replace
        // first message in queue by new SMsg

        if (q.cSize == q.cFilled)
        {
            pSQueue->pSMsg[q.cBegin] = SMsg;
            q.cBegin++;                             // Update pointer
            if (q.cBegin == q.cSize) q.cBegin = 0;

            OS_Flags.bEventError = 1;               // Set error flag

            goto EXIT;                              // Skip adding
        }

        //------------------------------------------------------
        // There is a free room in queue.
        // Add new message at end of queue.

        temp = q.cBegin + q.cFilled;
        if (temp >= q.cSize) temp -= q.cSize;
        pSQueue->pSMsg[temp] = SMsg;
        q.cFilled++;                                // Update fillness

    EXIT:
        pSQueue->Q = q;

        __OS_QUEUE_RI();

    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_SQueue_Send_DEFINED)
//------------------------------------------------------------------------------






/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_IntSendSQueue (OST_SQUEUE *pSQueue, OST_SMSG SMsg)                 *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Copy of _OS_SQueue_Send to be called from interrupt         *
 *                                                                              *
 *  parameters:     pSQueue      - pointer to queue descriptor                  *
 *                  SMsg        - simple message to be added                    *
 *                                                                              *
 *  on return:      OS_IsEventError() return 1, if first message was pushed out *
 *                                                                              *
 *  Overloaded in:  -                                                           *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#if defined(OS_ENABLE_INT_QUEUE) && !defined(_OS_IntSendSQueue_DEFINED)
//------------------------------------------------------------------------------

    void _OS_IntSendSQueue (OST_SQUEUE *pSQueue, OST_SMSG SMsg)
    {
        OST_QUEUE_CONTROL   q;
        _OST_INT_TYPE temp;

        q = pSQueue->Q;
        OS_Flags.bEventError = 0;

        //------------------------------------------------------
        // If there is no free room in queue, then replace
        // first message in queue by new SMsg

        if (q.cSize == q.cFilled)
        {
            pSQueue->pSMsg[q.cBegin] = SMsg;
            q.cBegin++;
            if (q.cBegin == q.cSize) q.cBegin = 0;

            OS_Flags.bEventError = 1;
            goto EXIT;
        }

        //------------------------------------------------------
        // There is a free room in queue.
        // Add new message at end of queue.

        temp = q.cBegin + q.cFilled;
        if (temp >= q.cSize) temp -= q.cSize;
        pSQueue->pSMsg[temp] = SMsg;
        q.cFilled++;

    EXIT:
        pSQueue->Q = q;
    }

//------------------------------------------------------------------------------
#endif  // (OS_ENABLE_INT_QUEUE) && !defined(_OS_IntSendSQueue_DEFINED)
//------------------------------------------------------------------------------









/*
 ********************************************************************************
 *                                                                              *
 *  OST_SMSG _OS_GetSQueue (OST_SQUEUE *pSQueue)                                *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_AcceptSQueue)                                    *
 *                                                                              *
 *                  Get first simple message from queue. Before calling this    *
 *                  function be sure that queue is not empty (OS_AcceptSQueue   *
 *                  does it automatically). After execution this function first *
 *                  message will be deleted from queue.                         *
 *                                                                              *
 *  parameters:     pSQueue      - pointer to queue descriptor                  *
 *                                                                              *
 *  on return:      first message from queue                                    *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#if !defined(_OS_GetSQueue_DEFINED)
//------------------------------------------------------------------------------

    OST_SMSG _OS_GetSQueue (OST_SQUEUE *pSQueue)
    {
        OST_QUEUE_CONTROL   q;
        _OST_INT_TYPE temp;

        q = pSQueue->Q;
        temp = q.cBegin;
        q.cBegin++;

        if (q.cBegin >= q.cSize)    q.cBegin = 0;

        q.cFilled--;
        pSQueue->Q = q;

        return  pSQueue->pSMsg[temp];
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_GetSQueue_DEFINED)
//------------------------------------------------------------------------------
#endif




















//------------------------------------------------------------------------------
#if defined(OS_ENABLE_QUEUE)
//------------------------------------------------------------------------------

/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Queue_Send (OST_QUEUE *pQueue, OST_MSG Msg)                        *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service _OS_Queue_Send)                                     *
 *                                                                              *
 *                  Adds message into queue of pointers to messages. Deletes    *
 *                  first message if there is no free room to add new message.  *
 *                  Service OS_Queue_Send before adding new message checks for  *
 *                  free room. Thus messages will not deleted accidentally.     *
 *                                                                              *
 *                                                                              *
 *  parameters:     pQueue      - pointer to queue descriptor                   *
 *                  Msg        - pointer to  message to be added                *
 *                                                                              *
 *  on return:      OS_IsEventError() return 1, if first message was pushed out *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#if !defined(_OS_Queue_Send_DEFINED)
//------------------------------------------------------------------------------

    void _OS_Queue_Send (OST_QUEUE *pQueue, OST_MSG Msg)
    {

        OST_QUEUE_CONTROL   q;
        _OST_INT_TYPE temp;

        __OS_QUEUE_DI();
        q = pQueue->Q;
        OS_Flags.bEventError = 0;

        //------------------------------------------------------
        // If there is no free room in queue, then replace
        // first message in queue by new SMsg

        if (q.cSize == q.cFilled)
        {
            pQueue->pMsg[q.cBegin] = Msg;
            q.cBegin++;
            if (q.cBegin == q.cSize) q.cBegin = 0;

            OS_Flags.bEventError = 1;
            goto EXIT;
        }


        //------------------------------------------------------
        // There is a free room in queue.
        // Add new message at end of queue.

        temp = q.cBegin + q.cFilled;
        if (temp >= q.cSize) temp -= q.cSize;
        pQueue->pMsg[temp] = Msg;
        q.cFilled++;

    EXIT:

        pQueue->Q = q;
        __OS_QUEUE_RI();
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_Queue_Send_DEFINED)
//------------------------------------------------------------------------------








/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_IntSendQueue (OST_QUEUE *pQueue, OST_MSG Msg)                      *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Copy of _OS_Queue_Send to be called from interrupt          *
 *                                                                              *
 *  parameters:     pQueue      - pointer to queue descriptor                   *
 *                  Msg        - pointer to message to be added                 *
 *                                                                              *
 *  on return:      OS_IsEventError() return 1, if first message was pushed out *
 *                                                                              *
 *  Overloaded in:  -                                                           *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if defined(OS_ENABLE_INT_QUEUE) && !defined(_OS_IntSendQueue_DEFINED)
//------------------------------------------------------------------------------

    void _OS_IntSendQueue (OST_QUEUE *pQueue, OST_MSG Msg)
    {

        OST_QUEUE_CONTROL   q;
        _OST_INT_TYPE temp;

        q = pQueue->Q;
        OS_Flags.bEventError = 0;

        //------------------------------------------------------
        // If there is no free room in queue, then replace
        // first message in queue by new SMsg

        if (q.cSize == q.cFilled)
        {
            pQueue->pMsg[q.cBegin] = Msg;
            q.cBegin++;
            if (q.cBegin == q.cSize) q.cBegin = 0;

            OS_Flags.bEventError = 1;
            goto EXIT;
        }

        //------------------------------------------------------
        // There is a free room in queue.
        // Add new message at end of queue.

        temp = q.cBegin + q.cFilled;
        if (temp >= q.cSize) temp -= q.cSize;
        pQueue->pMsg[temp] = Msg;
        q.cFilled++;

    EXIT:

        pQueue->Q = q;
    }

//------------------------------------------------------------------------------
#endif  // (OS_ENABLE_INT_QUEUE) && !defined(_OS_IntSendQueue_DEFINED)
//------------------------------------------------------------------------------









/*
 ********************************************************************************
 *                                                                              *
 *  OST_MSG _OS_GetQueue (OST_QUEUE *pQueue)                                    *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_AcceptQueue)                                     *
 *                                                                              *
 *                  Get first pointer to message from queue. Before calling this*
 *                  function be sure that queue is not empty (OS_AcceptQueue does*
 *                  it automatically). After execution this function first      *
 *                  message will be deleted from queue.                         *
 *                                                                              *
 *  parameters:     pQueue      - pointer to queue descriptor                   *
 *                                                                              *
 *  on return:      first message from queue                                    *
 *                                                                              *
 *  Overloaded in:  "port\osa_picc12.c"                                         *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#if !defined(_OS_GetQueue_DEFINED)
//------------------------------------------------------------------------------

    OST_MSG _OS_GetQueue (OST_QUEUE *pQueue)
    {
        OST_QUEUE_CONTROL   q;
        _OST_INT_TYPE temp;

        q = pQueue->Q;
        temp = q.cBegin;
        q.cBegin++;

        if (q.cBegin >= q.cSize)    q.cBegin = 0;

        q.cFilled--;
        pQueue->Q = q;

        return  pQueue->pMsg[temp];
    }

//------------------------------------------------------------------------------
#endif  // !defined(_OS_GetQueue_DEFINED)
//------------------------------------------------------------------------------
#endif  // OS_ENABLE_QUEUE
//------------------------------------------------------------------------------


















